<template>
	<div class="player" v-show="playlist.length">
		<transition
			name="normal"
			@enter="enter"
			@after-enter="afterEnter"
			@leave="leave"
			@after-leave="afterLeave"
		>
			<div class="normal-player" v-show="fullScreen">
				<div class="background">
					<img :src="currentSong.pic" alt="cover" />
				</div>
				<div class="top">
					<div class="back">
						<i class="icon-back" @click="back"></i>
					</div>
					<h1 class="title" v-html="currentSong.name"></h1>
					<h2 class="subtitle" v-html="currentSong.singer"></h2>
				</div>
				<div
					class="middle"
					@touchstart.prevent="middleTouchStart"
					@touchmove.prevent="middleTouchMove"
					@touchend="middleTouchEnd"
				>
					<div ref="middleL" class="middle-l">
						<div ref="cdWrapper" class="cd-wrapper">
							<div class="cd" :class="cls">
								<img
									:src="currentSong.pic"
									class="image"
									alt="pic"
								/>
							</div>
						</div>
						<div class="playing-lyric-wrapper">
			              <div class="playing-lyric">{{playingLyric}}</div>
			            </div>
					</div>
					<scroll
						ref="lyricList"
						class="middle-r"
						:data="currentLyric && currentLyric.lines">
						<div class="lyric-wrapper">
							<div v-if="currentLyric">
								<p
									ref="lyricLine"
									v-for="(line, index) in currentLyric.lines"
									:key="line.time"
									class="text"
									:class="{'current': currentLineNum === index}"
								>{{line.txt}}</p>
							</div>
						</div>
					</scroll>
				</div>
				<div class="bottom">
					<div class="dot-wrapper">
						<span class="dot" :class="{'active': currentShow === 'cd'}"></span>
						<span class="dot" :class="{'active': currentShow === 'lyric'}"></span>
					</div>
					<div class="progress-wrapper">
						<span class="time time-l">{{formatTime(currentTime)}}</span>
						<div class="progress-bar-wrapper">
							<progress-bar
								:percent="percent"
								@percentChange="onPercentChange"
							></progress-bar>
						</div>
						<span class="time time-r">{{formatTime(totalTime)}}</span>
					</div>
		          	<div class="operators">
		          		<div class="icon i-left" @click="changeMode">
							<i :class="iconMode"></i>
		          		</div>
		          		<div class="icon i-left" :class="disableCls">
							<i class="icon-prev" @click="prev"></i>
		          		</div>
		          		<div class="icon i-center" :class="disableCls">
							<i @click="togglePlaying" :class="playStyle"></i>
		          		</div>
		          		<div class="icon i-right" :class="disableCls">
							<i class="icon-next" @click="next"></i>
		          		</div>
		          		<div class="icon i-right">
							<i
								class="icon"
								:class="getFavoriteIcon(currentSong)"
								@click="toggleFavorite(currentSong)"
							></i>
		          		</div>
		          	</div>
				</div>
			</div>
		</transition>
		<transition name="mini">
			<div class="mini-player" v-show="!fullScreen && currentSong.pic" @click="open">
				<div class="icon">
					<img
						:src="currentSong.pic"
						width="40"
						height="40"
						:class="cls"
						alt="icon"
					/>
				</div>
				<div class="text">
					<h2 class="name" v-html="currentSong.name"></h2>
					<p class="desc" v-html="currentSong.singer"></p>
				</div>
				<div class="control">
					<progress-circle :radius="radius" :percent="percent">
						<i
							:class="miniPlayStyle"
							class="icon-mini"
							@click.stop="togglePlaying"
						></i>
					</progress-circle>
				</div>
				<div class="control" @click.stop="showPlaylist">
					<i class="icon-playlist"></i>
				</div>
			</div>
		</transition>
		<play-list ref="playlist"></play-list>
		<audio
			:src="currentSong.url"
			ref="audio"
			@play="ready"
			@error="error"
			@timeupdate="updateTime"
			@ended="end"
		>
		</audio>
	</div>
</template>

<script>
	import Scroll from '@/base/scroll/scroll';
	import ProgressBar from '@/base/progress-bar/progress-bar';
	import ProgressCircle from '@/base/progress-circle/progress-circle';
	import PlayList from '@/components/playlist/playlist';
	import { prefixStyle } from '@/common/js/dom';
	import { playMode } from '@/common/js/config';
	import { getLyric } from '@/service/song';
	import { playerMixin } from '@/common/js/mixin';
	import Lyric from 'lyric-parser';
	import animations from 'create-keyframe-animation';
	import { mapActions, mapGetters, mapMutations } from 'vuex';

	const transform = prefixStyle('transform');
	const transitionDuration = prefixStyle('transitionDuration');

	export default {
		name: 'Player',
		mixins: [playerMixin],
		data() {
			return {
				songReady: false,
				currentTime: 0,
				totalTime: 0,
				radius: 32,
				currentLyric: null,
				currentLineNum: 0,
				currentShow: 'cd',
				playingLyric: null
			}
		},
		created() {
			this.touch = {};
		},
		computed: {
			cls() {
				return this.playing ? 'play' : 'play pause';
			},
			playStyle() {
				return this.playing ? 'icon-pause' : 'icon-play';
			},
			miniPlayStyle() {
				return this.playing ? 'icon-pause-mini' : 'icon-play-mini';
			},
			disableCls() {
				return this.songReady ? '' : 'disable';
			},
			percent() {
				return this.currentTime / this.totalTime;
			},
			...mapGetters([
				'fullScreen',
				'playing',
				'lyric',
				'currentIndex'
			])
		},
		watch: {
			currentSong(newSong, oldSong) {
				if (!newSong.id) return;
				if (newSong.id === oldSong.id) return;
				if (this.currentLyric) {
					this.currentLyric.stop();
					this.currentTime = 0;
					this.playingLyric = '';
					this.currentLineNum = 0;
				}
				clearTimeout(this.timer);
				this.timer = setTimeout(() => {
					this.$refs.audio.play();
					this.getLyric(newSong);
				}, 1e3);
			},
			playing(newPlaying) {
				const audio = this.$refs.audio;
				this.$nextTick(() => {
					newPlaying ? audio.play() : audio.pause();
				});
			}
		},
		components: {
			ProgressBar,
			ProgressCircle,
			Scroll,
			PlayList
		},
		methods: {
			back() {
				this.setFullScreen(false);
			},
			open() {
				this.setFullScreen(true);
			},
			enter(el, done) {
				const { x, y, scale } = this.getPosAndScale();
				let animation = {
					0: {
						transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`
					},
					60: {
						transform: `translate3d(0, 0, 0) scale(1.1)`
					},
					100: {
						transform: `translate3d(0, 0, 0) scale(1)`
					}
				};
				animations.registerAnimation({
					name: 'move',
					animation,
					presets: {
						duration: 400,
						easing: 'linear'
					}
				});
				animations.runAnimation(this.$refs.cdWrapper, 'move', done);
			},
			afterEnter() {
				animations.unregisterAnimation('move');
				this.$refs.cdWrapper.style.animation = '';
			},
			leave(el, done) {
				this.$refs.cdWrapper.style.transition = 'all 0.4s';
				const { x, y, scale } = this.getPosAndScale();
				this.$refs.cdWrapper.style[transform] = `translate3d(${x}px, ${y}px, 0) scale(${scale})`;
				this.$refs.cdWrapper.addEventListener('transitionend', done);
			},
			afterLeave() {
				this.$refs.cdWrapper.style.transition = '';
				this.$refs.cdWrapper.style[transform] = '';
			},
			getPosAndScale() {
				const targetWidth = 40;
				const paddingLeft = 40;
				const paddingBottom = 30;
				const paddingTop = 80;
				const width = window.innerWidth * 0.8;
				const scale = targetWidth / width;
				const x = -(window.innerWidth / 2 - paddingLeft);
				const y = window.innerHeight - paddingTop - width / 2 - paddingBottom;
				return {
					x,
					y,
					scale
				}
			},
			onPercentChange(percent) {
				const currentTime = this.totalTime * percent;
				this.$refs.audio.currentTime = currentTime;
				if (!this.playing) {
					this.togglePlaying();
				}
				if (this.currentLyric) {
					this.currentLyric.seek(currentTime * 1000);
				}
			},
			togglePlaying() {
				if (!this.songReady) return;
				this.setPlayingState(!this.playing);
				if (this.currentLyric) {
					this.currentLyric.togglePlay();
				}
			},
			prev() {
				if (!this.songReady) return;
				let len = this.playlist.length;
				if (len === 1) {
					this.loop();
					return;
				} else {
					let index = this.currentIndex - 1;
					if (index <= 0) {
						index = len - 1;
					}
					this.setCurrentIndex(index);
					if (!this.playing) {
						this.togglePlaying();
					}
					const currentPlayingSong = this.playlist[index];
					this.setCurrentSong(currentPlayingSong);
				}
			},
			next() {
				if (!this.songReady) return;
				let len = this.playlist.length;
				if (len === 1) {
					this.loop();
					return;
				} else {
					let index = this.currentIndex + 1;
					if (index >= len - 1) {
						index = 0;
					}
					this.setCurrentIndex(index);
					if (!this.playing) {
						this.togglePlaying();
					}
					const currentPlayingSong = this.playlist[index];
					this.setCurrentSong(currentPlayingSong);
				}
			},
			ready() {
				setTimeout(() => {
					this.songReady = true;
					this.totalTime = this.$refs.audio.duration;
					this.savePlayHistory(this.currentSong);
				}, 1e3)
			},
			error() {
				this.songReady = true;
			},
			updateTime(e) {
				this.currentTime = e.target.currentTime;
			},
			formatTime(time) {
				if (time) {
					const temp = time | 0;
					const minute = (temp / 60 | 0).toString().padStart(2, '0');
	      			const second = (temp % 60).toString().padStart(2, '0');
	      			return `${minute}:${second}`;
				} else {
					return '00:00';
				}
			},
			end() {
				if (this.mode === playMode.loop) {
					this.loop();
				} else {
					this.next();
				}
			},
			loop() {
				const audio = this.$refs.audio;
				audio.currentTime = 0;
				audio.play();
				if (this.currentLyric) {
					this.currentLyric.seek(0);
				}
			},
			async getLyric(song) {
				const lyric = await getLyric(song);
				this.currentLyric = new Lyric(lyric, this.handleLyric);
				if (!lyric) {
					this.currentLyric = null;
					this.playingLyric = '';
					this.currentLineNum = 0;
				}
				if (this.playing) {
					this.currentLyric.play();
				}
			},
			handleLyric({lineNum, txt}) {
				this.currentLineNum = lineNum;
				if (lineNum > 5) {
					let lineEl = this.$refs.lyricLine[lineNum - 5];
					this.$refs.lyricList.scrollToElement(lineEl, 1e3);
				} else {
					this.$refs.lyricList.scrollTo(0, 0, 1e3);
				}
				this.playingLyric = txt;
			},
			middleTouchStart(e) {
				this.touch.initiated = true;
				const touch = e.touches[0];
				this.touch.startX = touch.pageX;
				this.touch.startY = touch.pageY;
			},
			middleTouchMove(e) {
				if (!this.touch.initiated) {
					return;
				}
				const touch = e.touches[0];
				const deltaX = touch.pageX - this.touch.startX;
				const deltaY = touch.pageY - this.touch.startY;
				if (Math.abs(deltaY) > Math.abs(deltaX)) return;
				const left = this.currentShow === 'cd' ? 0 : -window.innerWidth;
				const offsetWidth = Math.min(0, Math.max(-window.innerWidth, left + deltaX));
				this.touch.percent = Math.abs(offsetWidth / window.innerWidth);
				this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px,0,0)`;
				this.$refs.lyricList.$el.style[transitionDuration] = 0;
				this.$refs.middleL.style.opacity = 1 - this.touch.percent;
				this.$refs.middleL.style[transitionDuration] = 0;
			},
			middleTouchEnd() {
				let offsetWidth;
				let opacity;
				if (this.currentShow === 'cd') {
					if (this.touch.percent > 0.1) {
						offsetWidth = -window.innerWidth;
						this.currentShow = 'lyric';
						opacity = 0;
					} else {
						offsetWidth = 0;
						opacity = 1;
					}
				} else {
					if (this.touch.percent < 0.9) {
						offsetWidth = 0;
						this.currentShow = 'cd';
						opacity = 1;
					} else {
						offsetWidth = -window.innerWidth;
						opacity = 0;
					}
				}
				const time = 300;
				this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px, 0, 0)`;
				this.$refs.lyricList.$el.style[transitionDuration] = `${time}ms`;
				this.$refs.middleL.style.opacity = opacity;
				this.$refs.middleL.style[transitionDuration] = `${time}ms`;
			},
			showPlaylist() {
				this.$refs.playlist.show();
			},
			...mapMutations({
				setFullScreen: 'SET_FULL_SCREEN',
				setCurrentSong: 'SET_CURRENT_SONG',
				setPlayingState: 'SET_PLAYING_STATE'
			}),
			...mapActions([
				'selectPlay',
				'savePlayHistory'
			])
		}
	}
</script>

<style lang="stylus" scoped>
	@import "../../common/stylus/variable"
	@import "../../common/stylus/mixin"

	.player
		.normal-player
			position: fixed
			left: 0
			top: 0
			right: 0
			bottom: 0
			z-index: 150
			background: $color-background
			.background
				position: absolute
				left: 0
				top: 0
				z-index: -1
				width: 100%
				height: 100%
				opacity: 0.6
				filter: blur(20px)
			.top
				position: relative
				margin-bottom: 25px
				.back
					position: absolute
					left: 6px
					top: 0
					z-index: 50
					.icon-back
						display: block
						padding: 9px
						font-size: $font-size-large-x
						color: $color-theme
						transform: rotate(-90deg)
				.title
					width: 70%
					margin: 0 auto
					line-height: 40px
					text-align: center
					no-wrap()
					font-size: $font-size-large
					color: $color-text
				.subtitle
					height: 20px
					line-height: 20px
					text-align: center
					font-size: $font-size-medium
					color: $color-text
					overflow: hidden
					text-overflow: ellipsis
					padding: 0 5px
			.middle
				position: fixed
				width: 100%
				top: 80px
				bottom: 170px
				white-space: nowrap
				font-size: 0
				.middle-l
					display: inline-block
					vertical-align: top
					position: relative
					width: 100%
					height: 0
					padding-top: 80%
					.cd-wrapper
						position: absolute
						left: 10%
						top: 0
						width: 80%
						height: 100%
						.cd
							width: 100%
							height: 100%
							box-sizing: border-box
							border: 10px solid rgba(255, 255, 255, 0.1)
							border-radius: 50%
							&.play
								animation: rotate 20s linear infinite
							&.pause
								animation-play-state: paused
							.image
								position: absolute
								left: 0
								top: 0
								width: 100%
								height: 100%
								border-radius: 50%
					.playing-lyric-wrapper
						width: 80%
						margin: 30px auto 0 auto
						overflow: hidden
						text-align: center
						.playing-lyric
							height: 20px
							line-height: 20px
							font-size: $font-size-medium
							color: $color-text-l
				.middle-r
					display: inline-block
					vertical-align: top
					width: 100%
					height: 100%
					overflow: hidden
					.lyric-wrapper
						width: 80%
						margin: 0 auto
						overflow: hidden
						text-align: center
						.text
							line-height: 32px
							color: $color-text-l
							font-size: $font-size-medium
							&.current
								color: $color-text
			.bottom
				position: absolute
				bottom: 50px
				width: 100%
				.dot-wrapper
					text-align: center
					font-size: 0
					.dot
						display: inline-block
						vertical-align: middle
						margin: 0 4px
						width: 8px
						height: 8px
						border-radius: 50%
						background: $color-text-l
						&.active
							width: 20px
							border-radius: 5px
							background: $color-text-ll
				.progress-wrapper
					display: flex
					align-items: center
					width: 80%
					margin: 0 auto
					padding: 10px 0
					.time
						color: $color-text
						font-size: $font-size-small
						flex: 0 0 30px
						line-height: 30px
						width: 30px
						&.time-l
							text-align: left
						&.time-r
							text-align: right
					.progress-bar-wrapper
						flex: 1
						margin: 0 1.5% 0 1.5%
				.operators
					display: flex
					align-items: center
					.icon
						flex: 1
						color: $color-theme
						&.disable
							color: $color-theme-d
						i
							font-size: 30px
					.i-left
						text-align: right
					.i-center
						padding: 0 20px
						text-align: center
						i
							font-size: 40px
					.i-right
						text-align: left
					.icon-favorite
						color: $color-sub-theme
			&.normal-enter-active, &.normal-leave-active
				transition: all 0.4s
				.top, .bottom
					transition: all 0.4s cubic-bezier(0.86, 0.18, 0.82, 1.32)
			&.normal-enter, &.normal-leave-to
				opacity: 0
				.top
					transform: translate3d(0, -100px, 0)
				.bottom
					transform: translate3d(0, 100px, 0)

		.mini-player
			display: flex
			align-items: center
			position: fixed
			left: 0
			bottom: 0
			z-index: 180
			width: 100%
			height: 60px
			background: $color-highlight-background
			&.mini-enter-active, &.mini-leave-active
				transition: all 0.4s
			&.mini-enter, &.mini-leave-to
				opacity: 0
			.icon
				flex: 0 0 40px
				width: 40px
				padding: 0 10px 0 20px
				img
					border-radius: 50%
					&.play
						animation: rotate 10s linear infinite
					&.pause
						animation-play-state: paused
			.text
				display: flex
				flex-direction: column
				justify-content: center
				flex: 1
				line-height: 20px
				overflow: hidden
				.name
					margin-bottom: 2px
					no-wrap()
					font-size: $font-size-medium
					color: $color-text
				.desc
					no-wrap()
					font-size: $font-size-small
					color: $color-text-d
			.control
				flex: 0 0 30px
				width: 30px
				padding: 0 10px
				.icon-play-mini, .icon-pause-mini, .icon-playlist
					font-size: 30px
					color: $color-theme-d
				.icon-mini
					font-size: 32px
					position: absolute
					left: 0
					top: 0
@keyframes rotate
	0%
		transform: rotate(0)
	100%
		transform: rotate(360deg)
</style>
